<!DOCTYPE html>



  


<html class="theme-next pisces use-motion" lang="zh-CN">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />







<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.1.3" rel="stylesheet" type="text/css" />


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon.png?v=5.1.3">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.png?v=5.1.3">


  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.png?v=5.1.3">


  <link rel="mask-icon" href="/images/logo.svg?v=5.1.3" color="#222">





  <meta name="keywords" content="Hexo, NexT" />




  


  <link rel="alternate" href="/atom.xml" title="理想-咸鱼" type="application/atom+xml" />






<meta name="description" content="一些简单的想法">
<meta property="og:type" content="website">
<meta property="og:title" content="理想-咸鱼">
<meta property="og:url" content="http://yoursite.com/index.html">
<meta property="og:site_name" content="理想-咸鱼">
<meta property="og:description" content="一些简单的想法">
<meta property="og:locale" content="zh_CN">
<meta property="article:author" content="bigfish">
<meta property="article:tag" content="python c c++ go lua 足球">
<meta name="twitter:card" content="summary">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Pisces',
    version: '5.1.3',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: 'Author'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://yoursite.com/"/>





  <title>理想-咸鱼</title>
  








<meta name="generator" content="Hexo 4.2.0"></head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-CN">

  
  
    
  

  <div class="container sidebar-position-left 
  page-home">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">理想-咸鱼</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle">鱼翔浅底</p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            Home
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            Archives
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
            
            Tags
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            Categories
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            
  <section id="posts" class="posts-expand">
    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2020/01/18/ubuntu12.04_bochs2.3.5_platform/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="bigfish">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="理想-咸鱼">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2020/01/18/ubuntu12.04_bochs2.3.5_platform/" itemprop="url">ubuntu12.04 上搭建 bochs2.3.5 调试环境</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2020-01-18T11:44:43+08:00">
                2020-01-18
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Words count in article&#58;</span>
                
                <span title="Words count in article">
                  834
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Reading time &asymp;</span>
                
                <span title="Reading time">
                  4
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          <!-- en_title: ubuntu12.04_bochs2.3.5_platform -->

<h1 id="ubuntu12-04-上搭建-bochs2-3-5-调试环境"><a href="#ubuntu12-04-上搭建-bochs2-3-5-调试环境" class="headerlink" title="ubuntu12.04 上搭建 bochs2.3.5 调试环境"></a>ubuntu12.04 上搭建 bochs2.3.5 调试环境</h1><p>在 ubuntu12.04 64 位环境下使用源码编译 bochs2.3.5 带 debug 带 gui 版本。</p>
          <!--noindex-->
          <div class="post-button text-center">
            <a class="btn" href="/2020/01/18/ubuntu12.04_bochs2.3.5_platform/#more" rel="contents">
              Read more &raquo;
            </a>
          </div>
          <!--/noindex-->
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2020/01/16/hello-world/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="bigfish">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="理想-咸鱼">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2020/01/16/hello-world/" itemprop="url">Hello World</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2020-01-16T16:03:01+08:00">
                2020-01-16
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Words count in article&#58;</span>
                
                <span title="Words count in article">
                  73
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Reading time &asymp;</span>
                
                <span title="Reading time">
                  1
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <p>Welcome to <a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/" target="_blank" rel="noopener">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html" target="_blank" rel="noopener">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues" target="_blank" rel="noopener">GitHub</a>.</p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">"My New Post"</span></span><br></pre></td></tr></table></figure>

<p>More info: <a href="https://hexo.io/docs/writing.html" target="_blank" rel="noopener">Writing</a></p>
<h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure>

<p>More info: <a href="https://hexo.io/docs/server.html" target="_blank" rel="noopener">Server</a></p>
<h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure>

<p>More info: <a href="https://hexo.io/docs/generating.html" target="_blank" rel="noopener">Generating</a></p>
<h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure>

<p>More info: <a href="https://hexo.io/docs/one-command-deployment.html" target="_blank" rel="noopener">Deployment</a></p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2020/01/15/hello-hexo/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="bigfish">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="理想-咸鱼">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2020/01/15/hello-hexo/" itemprop="url">hello,hexo</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2020-01-15T09:01:04+08:00">
                2020-01-15
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Words count in article&#58;</span>
                
                <span title="Words count in article">
                  2
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Reading time &asymp;</span>
                
                <span title="Reading time">
                  1
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <p>hello, hexo!</p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2020/01/08/uefi-security-boot--shi-xian-xi-jie/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="bigfish">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="理想-咸鱼">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2020/01/08/uefi-security-boot--shi-xian-xi-jie/" itemprop="url">uefi security boot 实现细节</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2020-01-08T11:10:46+08:00">
                2020-01-08
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Words count in article&#58;</span>
                
                <span title="Words count in article">
                  950
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Reading time &asymp;</span>
                
                <span title="Reading time">
                  3
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h1 id="uefi-security-boot-实现细节"><a href="#uefi-security-boot-实现细节" class="headerlink" title="uefi security boot 实现细节"></a>uefi security boot 实现细节</h1><h2 id="密钥体系"><a href="#密钥体系" class="headerlink" title="密钥体系"></a>密钥体系</h2><p><img src="https://github.com/TheBigFish/blog/raw/master/assets/security_boot_01.png" alt=""></p>
<h3 id="PKpub"><a href="#PKpub" class="headerlink" title="PKpub"></a>PKpub</h3><blockquote>
<p>Platform Key</p>
</blockquote>
<ul>
<li>确定平台所有者和平台固件之间的信任关系</li>
<li>BIOS 厂商 / OEM 创建这个 KEY</li>
<li>PK 是自签名</li>
<li>PKpriv 的所有者必须保证私钥的安全 </li>
</ul>
<h3 id="KEKpub"><a href="#KEKpub" class="headerlink" title="KEKpub"></a>KEKpub</h3><blockquote>
<p>Key Exchange Key </p>
</blockquote>
<ul>
<li>确定平台固件和操作系统之间的信任关系</li>
<li>KEY 用来对 db/dbx 进行签名</li>
<li>操作系统厂商提供</li>
<li>OEM 也可提供自己的 KEY 对 shell app 进行签名</li>
</ul>
<h3 id="DB"><a href="#DB" class="headerlink" title="DB"></a>DB</h3><blockquote>
<p>合规数据库</p>
</blockquote>
<ul>
<li>用来存放运行被执行的代码的签名，或者存储证书</li>
<li>OEM 可以把 IHV(独立硬件厂商）的签名放在 DB 里面，用来对第三方 OpROMs（UEFI CA) 进行校验</li>
<li>MS CA / UEFI CA 由 MSFT 提供.</li>
</ul>
<h3 id="DBX"><a href="#DBX" class="headerlink" title="DBX"></a>DBX</h3><blockquote>
<p>禁止数据库</p>
</blockquote>
<ul>
<li>用来存储禁止执行代码的签名</li>
<li>或者被禁止的公司的证书</li>
</ul>
<h3 id="KEY-的生成过程"><a href="#KEY-的生成过程" class="headerlink" title="KEY 的生成过程"></a>KEY 的生成过程</h3><p><img src="https://github.com/TheBigFish/blog/raw/master/assets/security_boot_02.png" alt=""></p>
<p>db 及 dbx 存放的是记录以及由某个 KEK 对该记录进行签名的数据，记录可以是：<br>1. efi 文件的 hash 值<br>2. efi 文件的签名数据<br>3. 对 efi 文件进行签名的证书</p>
<p>PK 由平台所有者持有，比如联想<br>KEK 由 PK 签名</p>
<p>db/dbx 数据进行更新时，bios 需要进行授权验证，验证该更新数据是否是由某个 KEK 进行签名，若验证通过，则将该条记录及其对应的签名数据存入 db/dbx。</p>
<p>MSCApri 以及 UEFICApri 可以对厂商提供的驱动进行签名。</p>
<h4 id="驱动更新流程"><a href="#驱动更新流程" class="headerlink" title="驱动更新流程"></a>驱动更新流程</h4><p>比如某个显卡厂商 Card</p>
<ul>
<li><p>使用自己的私钥 (Cardpri) 对自己的驱动进行签名生成 CardSign，(其证书为 CardCert)。</p>
</li>
<li><p>找 UEFICApri 对自己的数据（CardSign、CardCert）进行签名，生成 (（CardSign，UEFICApri_CardSign_Sign ）（CardCert，UEFICApri_CardCert_Sign ）） 。</p>
</li>
<li><p>调用 bios 接口进行更新，更新数据为 (（CardSign，UEFICApri_CardSign_Sign ）（CardCert，UEFICApri_CardCert_Sign ））</p>
</li>
<li><p>bios 中有 UEFICApub 对应的 KEY (UEFIKEKpub)</p>
</li>
<li><p>bios 遍历 KEK，使用 KEK 对 (（CardSign，UEFICApri_CardSign_Sign ）（CardCert，UEFICApri_CardCert_Sign ））进行验签</p>
</li>
<li><p>验签通过，将条目 （CardSign，UEFICApri_CardSign_Sign）、（CardCert，UEFICApri_CardCert_Sign）存入 db</p>
</li>
</ul>
<h4 id="efi-文件无签名数据的情况"><a href="#efi-文件无签名数据的情况" class="headerlink" title="efi 文件无签名数据的情况"></a>efi 文件无签名数据的情况</h4><p>按照上述校验流程，显卡厂商也可以不使用自己的私钥对驱动签名，而只是生成一个哈希值。<br>再使用 UEFICApri 对哈希值进行签名生成  (CardHash, UEFICApri_CardHash_Sign)。</p>
<p>要将该哈希及对应签名信息更新到 db 时，仍然要使用 KEK 验证 UEFICApri_CardHash_Sign。</p>
<p>使用 hash 值的 efi 文件在启动时，只需要验证该 efi 文件的 hash 是否匹配 db/dbx 中的某个 hash。</p>
<h4 id="驱动校验流程"><a href="#驱动校验流程" class="headerlink" title="驱动校验流程"></a>驱动校验流程</h4><ul>
<li>bios 验证显卡驱动</li>
<li>显卡驱动中由对应的签名的证书（CardCert）信息。</li>
<li>遍历 db 找到 CardCert</li>
<li>使用 CardCert 对 db 中所有类型为签名值的条目进行验证</li>
<li>如果某条验证通过，则校验通过</li>
</ul>
<h4 id="dbx"><a href="#dbx" class="headerlink" title="dbx"></a>dbx</h4><p>dbx 内容与 db 中数据格式一致，匹配 dbx 中数据则认为验证失败</p>
<h4 id="MSCApri-与-UEFICApri"><a href="#MSCApri-与-UEFICApri" class="headerlink" title="MSCApri 与 UEFICApri"></a>MSCApri 与 UEFICApri</h4><p>市面上已经有大量使用 MSCApri 以及 UEFICApri 签名的 efi。</p>
<p>要加入该体系，只需要，使用 PKpri 对 MSCApub 及 UEFICApub 进行签名，生成对应的两个 KEK:  MSKEKpub  UEFIKEKpub。</p>
<p>将该两个 KEK 加入 bios , 即可以支持已签名的 efi。</p>
<h4 id="OS-Loader"><a href="#OS-Loader" class="headerlink" title="OS Loader"></a>OS Loader</h4><blockquote>
<p>比如 grub</p>
</blockquote>
<p>OS Loader 使用 MSCApri 签名，对应的 MSCApub 存储于 db，同时 MSKEKpub 也内置于 bios。</p>
<h3 id="db-dbx-防篡改"><a href="#db-dbx-防篡改" class="headerlink" title="db/dbx 防篡改"></a>db/dbx 防篡改</h3><p>db/dbx 每条记录都是 数据以及使用 KEK 对该数据的签名。<br>bios 启动时，逐条遍历记录并验证签名。</p>
<h2 id="概括"><a href="#概括" class="headerlink" title="概括"></a>概括</h2><p>通过使用分级密钥体系</p>
<ul>
<li>平台所有者只持有 PKpri</li>
<li>各级板卡厂商及操作系统厂商可以使用各自的公私钥体系对数据进行签名</li>
<li>平台所有者通过签名各级厂商的公钥生成 KEK, 将平台所有者认为可信的厂商加入信任</li>
</ul>
<hr>
<p>Sync From: <a href="https://github.com/TheBigFish/blog/issues/15" target="_blank" rel="noopener">https://github.com/TheBigFish/blog/issues/15</a></p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2019/12/18/python--lei-han-shu-bang-ding-fang-fa-de-shi-xian/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="bigfish">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="理想-咸鱼">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2019/12/18/python--lei-han-shu-bang-ding-fang-fa-de-shi-xian/" itemprop="url">python 类函数绑定方法的实现</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2019-12-18T15:43:27+08:00">
                2019-12-18
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Words count in article&#58;</span>
                
                <span title="Words count in article">
                  612
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Reading time &asymp;</span>
                
                <span title="Reading time">
                  3
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h1 id="python-类函数绑定方法的实现"><a href="#python-类函数绑定方法的实现" class="headerlink" title="python 类函数绑定方法的实现"></a>python 类函数绑定方法的实现</h1><h2 id="实现一个函数描述器"><a href="#实现一个函数描述器" class="headerlink" title="实现一个函数描述器"></a>实现一个函数描述器</h2><blockquote>
<p>This means that all functions are non-data descriptors which return bound methods when they are invoked from an object.</p>
</blockquote>
<p>所有的函数都是一个无数据的描述器。类实例调用函数即触发描述器语法，该描述器在类实例被调用时，返回一个绑定的普通方法。</p>
<p>下面实现了一个纯 python 的描述器 BindFunction, 用来绑定方法 f_normal 到函数 f。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">D</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">f</span><span class="params">(self, name)</span>:</span></span><br><span class="line">        print(self, name)</span><br><span class="line">d=D()</span><br><span class="line">d.f(<span class="string">"hello"</span>)</span><br><span class="line">D.f(d, <span class="string">"hello"</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> types</span><br><span class="line"><span class="keyword">from</span> functools <span class="keyword">import</span> wraps</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">f_normal</span><span class="params">(self, name)</span>:</span></span><br><span class="line">    print(self, name)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BindFunction</span><span class="params">(object)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, func)</span>:</span></span><br><span class="line">        wraps(func)(self)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__call__</span><span class="params">(self, *args, **kwargs)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> self.__wrapped__(*args, **kwargs)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__get__</span><span class="params">(self, obj, objtype=None)</span>:</span></span><br><span class="line">        <span class="string">"Simulate func_descr_get() in Objects/funcobject.c"</span></span><br><span class="line">        <span class="keyword">if</span> obj <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">            <span class="keyword">return</span> self</span><br><span class="line">        <span class="keyword">return</span> types.MethodType(self,  obj)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">D</span>:</span></span><br><span class="line">    f = BindFunction(f_normal)</span><br><span class="line"></span><br><span class="line">d = D()</span><br><span class="line">d.f(<span class="string">"world"</span>)</span><br><span class="line">D.f(d, <span class="string">"world"</span>)</span><br></pre></td></tr></table></figure>

<p>类 BindFunction 也可以实现如下：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BindFunction</span><span class="params">(object)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, func)</span>:</span></span><br><span class="line">        self.func = func</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__get__</span><span class="params">(self, obj, objtype=None)</span>:</span></span><br><span class="line">        <span class="string">"Simulate func_descr_get() in Objects/funcobject.c"</span></span><br><span class="line">        <span class="keyword">if</span> obj <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">            <span class="keyword">return</span> self.func</span><br><span class="line">        <span class="keyword">return</span> types.MethodType(self.func,  obj)</span><br></pre></td></tr></table></figure>

<h2 id="Functions-and-Methods"><a href="#Functions-and-Methods" class="headerlink" title="Functions and Methods"></a>Functions and Methods</h2><p><a href="https://docs.python.org/3/howto/descriptor.html?highlight=types%20methodtype#functions-and-methods" target="_blank" rel="noopener">Functions and Methods</a></p>
<blockquote>
<pre><code>Python’s object oriented features are built upon a function based environment. Using non-data descriptors, the two are merged seamlessly.</code></pre></blockquote>
<pre><code>Class dictionaries store methods as functions. In a class definition, methods are written using def or lambda, the usual tools for creating functions. Methods only differ from regular functions in that the first argument is reserved for the object instance. By Python convention, the instance reference is called self but may be called this or any other variable name.

To support method calls, functions include the __get__() method for binding methods during attribute access. This means that all functions are non-data descriptors which return bound methods when they are invoked from an object. In pure Python, it works like this:

class Function(object):
    . . .
    def __get__(self, obj, objtype=None):
        &quot;Simulate func_descr_get() in Objects/funcobject.c&quot;
        if obj is None:
            return self
        return types.MethodType(self, obj)
Running the interpreter shows how the function descriptor works in practice:

&gt;&gt;&gt;
&gt;&gt;&gt; class D(object):
...     def f(self, x):
...         return x
...
&gt;&gt;&gt; d = D()

# Access through the class dictionary does not invoke __get__.
# It just returns the underlying function object.
&gt;&gt;&gt; D.__dict__[&apos;f&apos;]
&lt;function D.f at 0x00C45070&gt;

# Dotted access from a class calls __get__() which just returns
# the underlying function unchanged.
&gt;&gt;&gt; D.f
&lt;function D.f at 0x00C45070&gt;

# The function has a __qualname__ attribute to support introspection
&gt;&gt;&gt; D.f.__qualname__
&apos;D.f&apos;

# Dotted access from an instance calls __get__() which returns the
# function wrapped in a bound method object
&gt;&gt;&gt; d.f
&lt;bound method D.f of &lt;__main__.D object at 0x00B18C90&gt;&gt;

# Internally, the bound method stores the underlying function,
# the bound instance, and the class of the bound instance.
&gt;&gt;&gt; d.f.__func__
&lt;function D.f at 0x1012e5ae8&gt;
&gt;&gt;&gt; d.f.__self__
&lt;__main__.D object at 0x1012e1f98&gt;
&gt;&gt;&gt; d.f.__class__
&lt;class &apos;method&apos;&gt;</code></pre><hr>
<p>Sync From: <a href="https://github.com/TheBigFish/blog/issues/14" target="_blank" rel="noopener">https://github.com/TheBigFish/blog/issues/14</a></p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2019/07/17/codeblock--lian-jie--openssl--ku-wen-jian/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="bigfish">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="理想-咸鱼">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2019/07/17/codeblock--lian-jie--openssl--ku-wen-jian/" itemprop="url">codeblock 链接 openssl 库文件</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2019-07-17T10:33:13+08:00">
                2019-07-17
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Words count in article&#58;</span>
                
                <span title="Words count in article">
                  138
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Reading time &asymp;</span>
                
                <span title="Reading time">
                  1
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h1 id="codeblock-链接-openssl-库文件"><a href="#codeblock-链接-openssl-库文件" class="headerlink" title="codeblock 链接 openssl 库文件"></a>codeblock 链接 openssl 库文件</h1><h2 id="安装-codeblock"><a href="#安装-codeblock" class="headerlink" title="安装 codeblock"></a>安装 codeblock</h2><pre><code>版本为： codeblocks-17.12mingw-setup.exe
gcc: 5.1.0</code></pre><h2 id="安装-MSYS-1-0-10-exe"><a href="#安装-MSYS-1-0-10-exe" class="headerlink" title="安装 MSYS-1.0.10.exe"></a>安装 MSYS-1.0.10.exe</h2><pre><code>将 `CodeBlocks\MinGW` 下文件拷贝至 `msys\1.0\mingw`
gcc -v 输出版本号即成功</code></pre><h2 id="安装-perl-5"><a href="#安装-perl-5" class="headerlink" title="安装 perl 5"></a>安装 perl 5</h2><pre><code>strawberry-perl-5.30.0.1-64bit.msi</code></pre><h2 id="编译-openssl"><a href="#编译-openssl" class="headerlink" title="编译 openssl"></a>编译 openssl</h2><pre><code>- 版本 openssl-1.0.2j.tar.gz
- 编译
    - ./config
    - make
    - make test
    - make install
编译后文件位于 `msys\1.0\local\ssl`</code></pre><h2 id="配置-codeblock"><a href="#配置-codeblock" class="headerlink" title="配置 codeblock"></a>配置 codeblock</h2><pre><code>- project -&gt; build options -&gt; linker settings 增加：
    - libcrypto.a
    - libssl.a
    - libgdi32.a
- project -&gt; build options -&gt; search directories 增加：
    - msys\1.0\local\ssl\include</code></pre><p>完成 </p>
<hr>
<p>Sync From: <a href="https://github.com/TheBigFish/blog/issues/13" target="_blank" rel="noopener">https://github.com/TheBigFish/blog/issues/13</a></p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2019/01/16/tornado-yuan-ma-zhi-coroutine-fen-xi/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="bigfish">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="理想-咸鱼">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2019/01/16/tornado-yuan-ma-zhi-coroutine-fen-xi/" itemprop="url">tornado源码之coroutine分析</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2019-01-16T14:16:02+08:00">
                2019-01-16
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Words count in article&#58;</span>
                
                <span title="Words count in article">
                  2.4k
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Reading time &asymp;</span>
                
                <span title="Reading time">
                  10
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h1 id="tornado-源码之-coroutine-分析"><a href="#tornado-源码之-coroutine-分析" class="headerlink" title="tornado 源码之 coroutine 分析"></a>tornado 源码之 coroutine 分析</h1><blockquote>
<p>tornado 的协程原理分析<br>版本：4.3.0</p>
</blockquote>
<p>为支持异步，tornado 实现了一个协程库。</p>
<p>tornado 实现的协程框架有下面几个特点：</p>
<ol>
<li>支持 python 2.7，没有使用 yield from<br>特性，纯粹使用 yield 实现</li>
<li>使用抛出异常的方式从协程返回值</li>
<li>采用 Future 类代理协程（保存协程的执行结果，当携程执行结束时，调用注册的回调函数）</li>
<li>使用 IOLoop 事件循环，当事件发生时在循环中调用注册的回调，驱动协程向前执行</li>
</ol>
<p>由此可见，这是 python 协程的一个经典的实现。</p>
<p>本文将实现一个类似 tornado 实现的基础协程框架，并阐述相应的原理。</p>
<h2 id="外部库"><a href="#外部库" class="headerlink" title="外部库"></a>外部库</h2><p>使用 time 来实现定时器回调的时间计算。<br>bisect 的 insort 方法维护一个时间有限的定时器队列。<br>functools 的 partial 方法绑定函数部分参数。<br>使用 backports_abc 导入 Generator 来判断函数是否是生成器。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">import</span> bisect</span><br><span class="line"><span class="keyword">import</span> functools</span><br><span class="line"><span class="keyword">from</span> backports_abc <span class="keyword">import</span> Generator <span class="keyword">as</span> GeneratorType</span><br></pre></td></tr></table></figure>

<h2 id="Future"><a href="#Future" class="headerlink" title="Future"></a>Future</h2><blockquote>
<p>是一个穿梭于协程和调度器之间的信使。<br>提供了回调函数注册 (当异步事件完成后，调用注册的回调)、中间结果保存、结束结果返回等功能</p>
</blockquote>
<p>add_done_callback 注册回调函数，当 Future 被解决时，改回调函数被调用。<br>set_result 设置最终的状态，并且调用已注册的回调函数</p>
<p>协程中的每一个 yield 对应一个协程，相应的对应一个 Future 对象，譬如：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@coroutine</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">routine_main</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">yield</span> routine_simple()</span><br><span class="line"></span><br><span class="line">    <span class="keyword">yield</span> sleep(<span class="number">1</span>)</span><br></pre></td></tr></table></figure>

<p>这里的 routine_simple() 和 sleep(1) 分别对应一个协程，同时有一个 Future 对应。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Future</span><span class="params">(object)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self)</span>:</span></span><br><span class="line">        self._done = <span class="literal">False</span></span><br><span class="line">        self._callbacks = []</span><br><span class="line">        self._result = <span class="literal">None</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">_set_done</span><span class="params">(self)</span>:</span></span><br><span class="line">        self._done = <span class="literal">True</span></span><br><span class="line">        <span class="keyword">for</span> cb <span class="keyword">in</span> self._callbacks:</span><br><span class="line">            cb(self)</span><br><span class="line">        self._callbacks = <span class="literal">None</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">done</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> self._done</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">add_done_callback</span><span class="params">(self, fn)</span>:</span></span><br><span class="line">        <span class="keyword">if</span> self._done:</span><br><span class="line">            fn(self)</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            self._callbacks.append(fn)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">set_result</span><span class="params">(self, result)</span>:</span></span><br><span class="line">        self._result = result</span><br><span class="line">        self._set_done()</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">result</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> self._result</span><br></pre></td></tr></table></figure>

<h2 id="IOLoop"><a href="#IOLoop" class="headerlink" title="IOLoop"></a>IOLoop</h2><p>这里的 IOLoop 去掉了 tornado 源代码中 IO 相关部分，只保留了基本需要的功能，如果命名为 CoroutineLoop 更贴切。</p>
<p>这里的 IOLoop 提供基本的回调功能。它是一个线程循环，在循环中完成两件事：</p>
<ol>
<li>检测有没有注册的回调并执行</li>
<li>检测有没有到期的定时器回调并执行</li>
</ol>
<p>程序中注册的回调事件，最终都会在此处执行。<br>可以认为，协程程序本身、协程的驱动程序 都会在此处执行。<br>协程本身使用 wrapper 包装，并最后注册到 IOLoop 的事件回调，所以它的从预激到结束的代码全部在 IOLoop 回调中执行。<br>而协程预激后，会把 Runner.run() 函数注册到 IOLoop 的事件回调，以驱动协程向前运行。</p>
<p>理解这一点对于理解协程的运行原理至关重要。</p>
<p>这就是单线程异步的基本原理。因为都在一个线程循环中执行，我们可以不用处理多线程需要面对的各种繁琐的事情。</p>
<h3 id="IOLoop-start"><a href="#IOLoop-start" class="headerlink" title="IOLoop.start"></a>IOLoop.start</h3><p>事件循环，回调事件和定时器事件在循环中调用。</p>
<h3 id="IOLoop-run-sync"><a href="#IOLoop-run-sync" class="headerlink" title="IOLoop.run_sync"></a>IOLoop.run_sync</h3><p>执行一个协程。</p>
<p>将 run 注册进全局回调，在 run 中调用 func() 启动协程。<br>注册协程结束回调 stop, 退出 run_sync 的 start 循环，事件循环随之结束。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">IOLoop</span><span class="params">(object)</span>:</span>，</span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self)</span>:</span></span><br><span class="line">        self._callbacks = []</span><br><span class="line">        self._timers = []</span><br><span class="line">        self._running = <span class="literal">False</span></span><br><span class="line"></span><br><span class="line"><span class="meta">    @classmethod</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">instance</span><span class="params">(cls)</span>:</span></span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">not</span> hasattr(cls, <span class="string">"_instance"</span>):</span><br><span class="line">            cls._instance = cls()</span><br><span class="line">        <span class="keyword">return</span> cls._instance</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">add_future</span><span class="params">(self, future, callback)</span>:</span></span><br><span class="line">        future.add_done_callback(</span><br><span class="line">            <span class="keyword">lambda</span> future: self.add_callback(functools.partial(callback, future)))</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">add_timeout</span><span class="params">(self, when, callback)</span>:</span></span><br><span class="line">        bisect.insort(self._timers, (when, callback))</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">call_later</span><span class="params">(self, delay, callback)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> self.add_timeout(time.time() + delay, callback)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">add_callback</span><span class="params">(self, call_back)</span>:</span></span><br><span class="line">        self._callbacks.append(call_back)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">start</span><span class="params">(self)</span>:</span></span><br><span class="line">        self._running = <span class="literal">True</span></span><br><span class="line">        <span class="keyword">while</span> self._running:</span><br><span class="line"></span><br><span class="line">            <span class="comment"># 回调任务</span></span><br><span class="line">            callbacks = self._callbacks</span><br><span class="line">            self._callbacks = []</span><br><span class="line">            <span class="keyword">for</span> call_back <span class="keyword">in</span> callbacks:</span><br><span class="line">                call_back()</span><br><span class="line"></span><br><span class="line">            <span class="comment"># 定时器任务</span></span><br><span class="line">            <span class="keyword">while</span> self._timers <span class="keyword">and</span> self._timers[<span class="number">0</span>][<span class="number">0</span>] &lt; time.time():</span><br><span class="line">                task = self._timers[<span class="number">0</span>][<span class="number">1</span>]</span><br><span class="line">                <span class="keyword">del</span> self._timers[<span class="number">0</span>]</span><br><span class="line">                task()</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">stop</span><span class="params">(self)</span>:</span></span><br><span class="line">        self._running = <span class="literal">False</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">run_sync</span><span class="params">(self, func)</span>:</span></span><br><span class="line">        future_cell = [<span class="literal">None</span>]</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">()</span>:</span></span><br><span class="line">            <span class="keyword">try</span>:</span><br><span class="line">                future_cell[<span class="number">0</span>] = func()</span><br><span class="line">            <span class="keyword">except</span> Exception:</span><br><span class="line">                <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line">            self.add_future(future_cell[<span class="number">0</span>], <span class="keyword">lambda</span> future: self.stop())</span><br><span class="line"></span><br><span class="line">        self.add_callback(run)</span><br><span class="line"></span><br><span class="line">        self.start()</span><br><span class="line">        <span class="keyword">return</span> future_cell[<span class="number">0</span>].result()</span><br></pre></td></tr></table></figure>

<h2 id="coroutine"><a href="#coroutine" class="headerlink" title="coroutine"></a>coroutine</h2><p>协程装饰器。<br>协程由 coroutine 装饰，分为两类：</p>
<ol>
<li>含 yield 的生成器函数</li>
<li>无 yield 语句的普通函数</li>
</ol>
<p>装饰协程，并通过注册回调驱动协程运行。<br>程序中通过 yield coroutine_func() 方式调用协程。<br>此时，wrapper 函数被调用：</p>
<ol>
<li>获取协程生成器</li>
<li>如果是生成器，则<ol>
<li>调用 next() 预激协程</li>
<li>实例化 Runner()，驱动协程</li>
</ol>
</li>
<li>如果是普通函数，则<ol>
<li>调用 set_result() 结束协程</li>
</ol>
</li>
</ol>
<p>协程返回 Future 对象，供外层的协程处理。外部通过操作该 Future 控制协程的运行。<br>每个 yield 对应一个协程，每个协程拥有一个 Future 对象。</p>
<p>外部协程获取到内部协程的 Future 对象，如果内部协程尚未结束，将 Runner.run() 方法注册到 内部协程的 Future 的结束回调。<br>这样，在内部协程结束时，会调用注册的 run() 方法，从而驱动外部协程向前执行。</p>
<p>各个协程通过 Future 形成一个链式回调关系。</p>
<p>Runner 类在下面单独小节描述。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">coroutine</span><span class="params">(func)</span>:</span></span><br><span class="line">    <span class="keyword">return</span> _make_coroutine_wrapper(func)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 每个协程都有一个 future， 代表当前协程的运行状态</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_make_coroutine_wrapper</span><span class="params">(func)</span>:</span></span><br><span class="line"><span class="meta">    @functools.wraps(func)</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">wrapper</span><span class="params">(*args, **kwargs)</span>:</span></span><br><span class="line">        future = Future()</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            result = func(*args, **kwargs)</span><br><span class="line">        <span class="keyword">except</span> (Return, StopIteration) <span class="keyword">as</span> e:</span><br><span class="line">            result = _value_from_stopiteration(e)</span><br><span class="line">        <span class="keyword">except</span> Exception:</span><br><span class="line">            <span class="keyword">return</span> future</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            <span class="keyword">if</span> isinstance(result, GeneratorType):</span><br><span class="line">                <span class="keyword">try</span>:</span><br><span class="line">                    yielded = next(result)</span><br><span class="line">                <span class="keyword">except</span> (StopIteration, Return) <span class="keyword">as</span> e:</span><br><span class="line">                    future.set_result(_value_from_stopiteration(e))</span><br><span class="line">                <span class="keyword">except</span> Exception:</span><br><span class="line">                    <span class="keyword">pass</span></span><br><span class="line">                <span class="keyword">else</span>:</span><br><span class="line">                    Runner(result, future, yielded)</span><br><span class="line">                <span class="keyword">try</span>:</span><br><span class="line">                    <span class="keyword">return</span> future</span><br><span class="line">                <span class="keyword">finally</span>:</span><br><span class="line">                    future = <span class="literal">None</span></span><br><span class="line">        future.set_result(result)</span><br><span class="line">        <span class="keyword">return</span> future</span><br><span class="line">    <span class="keyword">return</span> wrapper</span><br></pre></td></tr></table></figure>

<h2 id="协程返回值"><a href="#协程返回值" class="headerlink" title="协程返回值"></a>协程返回值</h2><p>因为没有使用 yield from，协程无法直接返回值，所以使用抛出异常的方式返回。</p>
<p>python 2 无法在生成器中使用 return 语句。但是生成器中抛出的异常可以在外部 send() 语句中捕获。<br>所以，使用抛出异常的方式，将返回值存储在异常的 value 属性中，抛出。外部使用诸如：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">try</span>:</span><br><span class="line">    yielded = gen.send(value)</span><br><span class="line"><span class="keyword">except</span> Return <span class="keyword">as</span> e:</span><br></pre></td></tr></table></figure>

<p>这样的方式获取协程的返回值。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Return</span><span class="params">(Exception)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, value=None)</span>:</span></span><br><span class="line">        super(Return, self).__init__()</span><br><span class="line">        self.value = value</span><br><span class="line">        self.args = (value,)</span><br></pre></td></tr></table></figure>

<h2 id="Runner"><a href="#Runner" class="headerlink" title="Runner"></a>Runner</h2><p>Runner 是协程的驱动器类。</p>
<p>self.result_future 保存当前协程的状态。<br>self.future 保存 yield 子协程传递回来的协程状态。<br>从子协程的 future 获取协程运行结果 send 给当前协程，以驱动协程向前执行。</p>
<p>注意，会判断子协程返回的 future<br>如果 future 已经 set_result，代表子协程运行结束，回到 while Ture 循环，继续往下执行下一个 send；<br>如果 future 未 set_result，代表子协程运行未结束，将 self.run 注册到子协程结束的回调，这样，子协程结束时会调用 self.run，重新驱动协程执行。</p>
<p>如果本协程 send() 执行过程中，捕获到 StopIteration 或者 Return 异常，说明本协程执行结束，设置 result_future 的协程返回值，此时，注册的回调函数被执行。这里的回调函数为本协程的父协程所注册的 run()。<br>相当于唤醒已经处于 yiled 状态的父协程，通过 IOLoop 回调 run 函数，再执行 send()。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Runner</span><span class="params">(object)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, gen, result_future, first_yielded)</span>:</span></span><br><span class="line">        self.gen = gen</span><br><span class="line">        self.result_future = result_future</span><br><span class="line">        self.io_loop = IOLoop.instance()</span><br><span class="line">        self.running = <span class="literal">False</span></span><br><span class="line">        self.future = <span class="literal">None</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> self.handle_yield(first_yielded):</span><br><span class="line">            self.run()</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            self.running = <span class="literal">True</span></span><br><span class="line">            <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line"></span><br><span class="line">                <span class="keyword">try</span>:</span><br><span class="line">                    <span class="comment"># 每一个 yield 处看做一个协程，对应一个 Future</span></span><br><span class="line">                    <span class="comment"># 将该协程的结果 send 出去</span></span><br><span class="line">                    <span class="comment"># 这样外层形如  ret = yiled coroutine_func() 能够获取到协程的返回数据</span></span><br><span class="line">                    value = self.future.result()</span><br><span class="line">                    yielded = self.gen.send(value)</span><br><span class="line">                <span class="keyword">except</span> (StopIteration, Return) <span class="keyword">as</span> e:</span><br><span class="line">                    <span class="comment"># 协程执行完成，不再注册回调</span></span><br><span class="line">                    self.result_future.set_result(_value_from_stopiteration(e))</span><br><span class="line">                    self.result_future = <span class="literal">None</span></span><br><span class="line">                    <span class="keyword">return</span></span><br><span class="line">                <span class="keyword">except</span> Exception:</span><br><span class="line">                    <span class="keyword">return</span></span><br><span class="line">                <span class="comment"># 协程未执行结束，继续使用 self.run() 进行驱动</span></span><br><span class="line">                <span class="keyword">if</span> <span class="keyword">not</span> self.handle_yield(yielded):</span><br><span class="line">                    <span class="keyword">return</span></span><br><span class="line">        <span class="keyword">finally</span>:</span><br><span class="line">            self.running = <span class="literal">False</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">handle_yield</span><span class="params">(self, yielded)</span>:</span></span><br><span class="line">        self.future = yielded</span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">not</span> self.future.done():</span><br><span class="line">            <span class="comment"># 给 future 增加执行结束回调函数，这样，外部使用 future.set_result 时会调用该回调</span></span><br><span class="line">            <span class="comment"># 而该回调是把 self.run() 注册到 IOLoop 的事件循环</span></span><br><span class="line">            <span class="comment"># 所以，future.set_result 会把 self.run() 注册到 IOLoop 的事件循环，从而在下一个事件循环中调用</span></span><br><span class="line">            self.io_loop.add_future(</span><br><span class="line">                self.future, <span class="keyword">lambda</span> f: self.run())</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">False</span></span><br><span class="line">        <span class="keyword">return</span> <span class="literal">True</span></span><br></pre></td></tr></table></figure>

<h2 id="sleep"><a href="#sleep" class="headerlink" title="sleep"></a>sleep</h2><p>sleep 是一个延时协程，充分展示了协程的标准实现。</p>
<ul>
<li>创建一个 Future，并返回给外部协程；</li>
<li>外部协程发现是一个未完的状态，将 run() 注册到 Future 的完成回调，同时外部协程被挂起；</li>
<li>在设置的延时后，IOLoop 会回调 set_result 结束协程；</li>
<li>IOLoop 调用 run() 函数；</li>
<li>IOLoop 调用 send()，唤醒挂起的外部协程。</li>
</ul>
<p>流程如下图：</p>
<p><img src="https://github.com/TheBigFish/blog/raw/master/assets/tornado_simple_routine_1.png" alt=""></p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">sleep</span><span class="params">(duration)</span>:</span></span><br><span class="line">    f = Future()</span><br><span class="line">    IOLoop.instance().call_later(duration, <span class="keyword">lambda</span>: f.set_result(<span class="literal">None</span>))</span><br><span class="line">    <span class="keyword">return</span> f</span><br></pre></td></tr></table></figure>

<h2 id="运行"><a href="#运行" class="headerlink" title="运行"></a>运行</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@coroutine</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">routine_ur</span><span class="params">(url, wait)</span>:</span></span><br><span class="line">    <span class="keyword">yield</span> sleep(wait)</span><br><span class="line">    print(<span class="string">'routine_ur &#123;&#125; took &#123;&#125;s to get!'</span>.format(url, wait))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">@coroutine</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">routine_url_with_return</span><span class="params">(url, wait)</span>:</span></span><br><span class="line">    <span class="keyword">yield</span> sleep(wait)</span><br><span class="line">    print(<span class="string">'routine_url_with_return &#123;&#125; took &#123;&#125;s to get!'</span>.format(url, wait))</span><br><span class="line">    <span class="keyword">raise</span> Return((url, wait))</span><br><span class="line"></span><br><span class="line"><span class="comment"># 非生成器协程，不会为之生成单独的 Runner()</span></span><br><span class="line"><span class="comment"># coroutine 运行结束后，直接返回一个已经执行结束的 future</span></span><br><span class="line"><span class="meta">@coroutine</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">routine_simple</span><span class="params">()</span>:</span></span><br><span class="line">    print(<span class="string">"it is simple routine"</span>)</span><br><span class="line"></span><br><span class="line"><span class="meta">@coroutine</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">routine_simple_return</span><span class="params">()</span>:</span></span><br><span class="line">    print(<span class="string">"it is simple routine with return"</span>)</span><br><span class="line">    <span class="keyword">raise</span> Return(<span class="string">"value from routine_simple_return"</span>)</span><br><span class="line"></span><br><span class="line"><span class="meta">@coroutine</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">routine_main</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">yield</span> routine_simple()</span><br><span class="line"></span><br><span class="line">    <span class="keyword">yield</span> routine_ur(<span class="string">"url0"</span>, <span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">    ret = <span class="keyword">yield</span> routine_simple_return()</span><br><span class="line">    print(ret)</span><br><span class="line"></span><br><span class="line">    ret = <span class="keyword">yield</span> routine_url_with_return(<span class="string">"url1"</span>, <span class="number">1</span>)</span><br><span class="line">    print(ret)</span><br><span class="line"></span><br><span class="line">    ret = <span class="keyword">yield</span> routine_url_with_return(<span class="string">"url2"</span>, <span class="number">2</span>)</span><br><span class="line">    print(ret)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line">    IOLoop.instance().run_sync(routine_main)</span><br></pre></td></tr></table></figure>

<p>运行输出为：</p>
<pre><code>it is simple routine
routine_ur url0 took 1s to get!
it is simple routine with return
value from routine_simple_return
routine_url_with_return url1 took 1s to get!
(&apos;url1&apos;, 1)
routine_url_with_return url2 took 2s to get!
(&apos;url2&apos;, 2)</code></pre><p>可以观察到协程 sleep 已经生效。</p>
<h2 id="源码"><a href="#源码" class="headerlink" title="源码"></a>源码</h2><p><a href="https://github.com/TheBigFish/simple-python/blob/master/tornado/simple_coroutine.py" target="_blank" rel="noopener">simple_coroutine.py</a></p>
<h2 id="copyright"><a href="#copyright" class="headerlink" title="copyright"></a>copyright</h2><p>author：bigfish<br>copyright: <a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank" rel="noopener">许可协议 知识共享署名 - 非商业性使用 4.0 国际许可协议</a></p>
<hr>
<p>Sync From: <a href="https://github.com/TheBigFish/blog/issues/12" target="_blank" rel="noopener">https://github.com/TheBigFish/blog/issues/12</a></p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2019/01/03/rust--an-zhuang-ji-pei-zhi/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="bigfish">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="理想-咸鱼">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2019/01/03/rust--an-zhuang-ji-pei-zhi/" itemprop="url">rust 安装及配置</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2019-01-03T11:58:15+08:00">
                2019-01-03
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Words count in article&#58;</span>
                
                <span title="Words count in article">
                  115
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Reading time &asymp;</span>
                
                <span title="Reading time">
                  1
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h1 id="rust-安装及配置"><a href="#rust-安装及配置" class="headerlink" title="rust 安装及配置"></a>rust 安装及配置</h1><h2 id="配置参数"><a href="#配置参数" class="headerlink" title="配置参数"></a>配置参数</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">vi ~/.bashrc</span><br><span class="line"></span><br><span class="line"><span class="comment">#add</span></span><br><span class="line"><span class="built_in">export</span> CARGO_HOME=<span class="string">"~/.cargo/"</span></span><br><span class="line"><span class="built_in">export</span> RUSTBINPATH=<span class="string">"~/.cargo/bin"</span></span><br><span class="line"><span class="built_in">export</span> RUST=<span class="string">"~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu"</span></span><br><span class="line"><span class="built_in">export</span> RUST_SRC_PATH=<span class="string">"<span class="variable">$RUST</span>/lib/rustlib/src/rust/src"</span></span><br><span class="line"><span class="built_in">export</span> PATH=<span class="variable">$PATH</span>:<span class="variable">$RUSTBINPATH</span></span><br></pre></td></tr></table></figure>

<h2 id="修改源"><a href="#修改源" class="headerlink" title="修改源"></a>修改源</h2><h3 id="basrc"><a href="#basrc" class="headerlink" title=".basrc"></a>.basrc</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">vi ~/.bashrc</span><br><span class="line"><span class="comment">#add</span></span><br><span class="line"><span class="built_in">export</span> RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static</span><br><span class="line"><span class="built_in">export</span> RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup</span><br></pre></td></tr></table></figure>

<h3 id="config"><a href="#config" class="headerlink" title="config"></a>config</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">vi ~/.cargo/config</span><br><span class="line"><span class="comment">#add</span></span><br><span class="line">[source.crates-io]</span><br><span class="line">replace-with = <span class="string">'ustc'</span></span><br><span class="line"></span><br><span class="line">[source.ustc]</span><br><span class="line">registry = <span class="string">"git://mirrors.ustc.edu.cn/crates.io-index"</span></span><br></pre></td></tr></table></figure>

<h2 id="ch02-00-guessing-game-tutorial-md-编译错误"><a href="#ch02-00-guessing-game-tutorial-md-编译错误" class="headerlink" title="ch02-00-guessing-game-tutorial.md 编译错误"></a>ch02-00-guessing-game-tutorial.md 编译错误</h2><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// main.rst 文件顶部增加</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">extern</span> <span class="keyword">crate</span> rand;</span><br></pre></td></tr></table></figure>


<hr>
<p>Sync From: <a href="https://github.com/TheBigFish/blog/issues/11" target="_blank" rel="noopener">https://github.com/TheBigFish/blog/issues/11</a></p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/12/21/tornado-yuan-ma-zhi-stackcontext%EF%BC%88-er-%EF%BC%89/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="bigfish">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="理想-咸鱼">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/12/21/tornado-yuan-ma-zhi-stackcontext%EF%BC%88-er-%EF%BC%89/" itemprop="url">tornado源码之StackContext（二）</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2018-12-21T16:51:30+08:00">
                2018-12-21
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Words count in article&#58;</span>
                
                <span title="Words count in article">
                  1k
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Reading time &asymp;</span>
                
                <span title="Reading time">
                  4
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h1 id="tornado-源码之-StackContext（二）"><a href="#tornado-源码之-StackContext（二）" class="headerlink" title="tornado 源码之 StackContext（二）"></a>tornado 源码之 StackContext（二）</h1><blockquote>
<p>StackContext allows applications to maintain threadlocal-like state<br>that follows execution as it moves to other execution contexts.</p>
<p>an exception<br>handler is a kind of stack-local state and when that stack is suspended<br>and resumed in a new context that state needs to be preserved.</p>
<p>一个栈结构的上下文处理类<br>异常处理也是一个栈结构的上下文应用</p>
</blockquote>
<h2 id="contents"><a href="#contents" class="headerlink" title="contents"></a>contents</h2><ul>
<li><a href="#tornado-%E6%BA%90%E7%A0%81%E4%B9%8B-stackcontext%E4%BA%8C">tornado 源码之 StackContext（二）</a><ul>
<li><a href="#contents">contents</a></li>
<li><a href="#example-usage">example usage</a></li>
<li><a href="#head">head</a></li>
<li><a href="#state">_State</a></li>
<li><a href="#stackcontext">StackContext</a></li>
<li><a href="#exceptionstackcontext">ExceptionStackContext</a><ul>
<li><a href="#example">example</a></li>
</ul>
</li>
<li><a href="#nullcontext">NullContext</a></li>
<li><a href="#wrap">wrap</a></li>
<li><a href="#copyright">copyright</a></li>
</ul>
</li>
</ul>
<h2 id="example-usage"><a href="#example-usage" class="headerlink" title="example usage"></a>example usage</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@contextlib.contextmanager</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">die_on_error</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="keyword">yield</span></span><br><span class="line">    <span class="keyword">except</span>:</span><br><span class="line">        logging.error(<span class="string">"exception in asynchronous operation"</span>,exc_info=<span class="literal">True</span>)</span><br><span class="line">        sys.exit(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">with</span> StackContext(die_on_error):</span><br><span class="line">    <span class="comment"># Any exception thrown here *or in callback and its desendents*</span></span><br><span class="line">    <span class="comment"># will cause the process to exit instead of spinning endlessly</span></span><br><span class="line">    <span class="comment"># in the ioloop.</span></span><br><span class="line">    http_client.fetch(url, callback)</span><br><span class="line">ioloop.start()</span><br></pre></td></tr></table></figure>

<h2 id="head"><a href="#head" class="headerlink" title="head"></a>head</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> __future__ <span class="keyword">import</span> with_statement</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> contextlib</span><br><span class="line"><span class="keyword">import</span> functools</span><br><span class="line"><span class="keyword">import</span> itertools</span><br><span class="line"><span class="keyword">import</span> logging</span><br><span class="line"><span class="keyword">import</span> threading</span><br></pre></td></tr></table></figure>

<h2 id="State"><a href="#State" class="headerlink" title="_State"></a>_State</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">_State</span><span class="params">(threading.local)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self)</span>:</span></span><br><span class="line">        self.contexts = ()</span><br><span class="line">_state = _State()</span><br></pre></td></tr></table></figure>

<h2 id="StackContext"><a href="#StackContext" class="headerlink" title="StackContext"></a>StackContext</h2><ol>
<li>初始化时保持传入的上下文对象</li>
<li>__enter__<ol>
<li>保存当前的全局上下文</li>
<li>append 新的上下文到全局上下文</li>
<li>构造新的上下文</li>
<li>进入新的上下文 __enter__</li>
</ol>
</li>
<li>__exit__<ol>
<li>调用新的上下文 context __exit__</li>
<li>回复全局上下文</li>
</ol>
</li>
</ol>
<p>全局上下文保存整个执行程序的上下文（栈）<br>with StackContext(context) 使程序包裹在 (global_context, context) 上执行<br>执行完成后恢复全局上下文</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">StackContext</span><span class="params">(object)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, context_factory)</span>:</span></span><br><span class="line">        self.context_factory = context_factory</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__enter__</span><span class="params">(self)</span>:</span></span><br><span class="line">        self.old_contexts = _state.contexts</span><br><span class="line">        _state.contexts = (self.old_contexts +</span><br><span class="line">                           ((StackContext, self.context_factory),))</span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            self.context = self.context_factory()</span><br><span class="line">            self.context.__enter__()</span><br><span class="line">        <span class="keyword">except</span> Exception:</span><br><span class="line">            _state.contexts = self.old_contexts</span><br><span class="line">            <span class="keyword">raise</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__exit__</span><span class="params">(self, type, value, traceback)</span>:</span></span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            <span class="keyword">return</span> self.context.__exit__(type, value, traceback)</span><br><span class="line">        <span class="keyword">finally</span>:</span><br><span class="line">            _state.contexts = self.old_contexts</span><br></pre></td></tr></table></figure>

<h2 id="ExceptionStackContext"><a href="#ExceptionStackContext" class="headerlink" title="ExceptionStackContext"></a>ExceptionStackContext</h2><p>捕获上下文执行中抛出而又未被捕获的异常<br>作用类似 finally<br>用于执行在程序抛出异常后记录日志、关闭 socket 这些现场清理工作<br>如果 exception_handler 中返回 True, 表明异常已经被处理，不会再抛出</p>
<h3 id="example"><a href="#example" class="headerlink" title="example"></a>example</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> tornado <span class="keyword">import</span> ioloop</span><br><span class="line"><span class="keyword">import</span> tornado.stack_context</span><br><span class="line"><span class="keyword">import</span> contextlib</span><br><span class="line"></span><br><span class="line">ioloop = tornado.ioloop.IOLoop.instance()</span><br><span class="line"></span><br><span class="line"><span class="meta">@contextlib.contextmanager</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">context_without_catch</span><span class="params">()</span>:</span></span><br><span class="line">    print(<span class="string">"enter context"</span>)</span><br><span class="line">    <span class="keyword">yield</span></span><br><span class="line">    print(<span class="string">"exit context"</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">exception_handler</span><span class="params">(type, value, traceback)</span>:</span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">"catch uncaught exception:"</span>, type, value, traceback</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">True</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">main</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">with</span> tornado.stack_context.ExceptionStackContext(exception_handler):</span><br><span class="line">        <span class="keyword">with</span> tornado.stack_context.StackContext(context_without_catch):</span><br><span class="line">            <span class="keyword">print</span> <span class="number">0</span> / <span class="number">0</span></span><br><span class="line"></span><br><span class="line">main()</span><br><span class="line"><span class="comment"># enter context</span></span><br><span class="line"><span class="comment"># catch uncaught exception: &lt;type 'exceptions.ZeroDivisionError'&gt; integer division or modulo by zero &lt;traceback object at 0x0000000003321FC8&gt;</span></span><br></pre></td></tr></table></figure>

<p>__exit__ 中捕获 with 语句所包裹的程序执行中所抛出的异常，调用注册的 exception_handler 进行处理<br>exception_handler 返回 True，则异常不会蔓延</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ExceptionStackContext</span><span class="params">(object)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, exception_handler)</span>:</span></span><br><span class="line">        self.exception_handler = exception_handler</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__enter__</span><span class="params">(self)</span>:</span></span><br><span class="line">        self.old_contexts = _state.contexts</span><br><span class="line">        _state.contexts = (self.old_contexts +</span><br><span class="line">                           ((ExceptionStackContext, self.exception_handler),))</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__exit__</span><span class="params">(self, type, value, traceback)</span>:</span></span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            <span class="keyword">if</span> type <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line">                <span class="keyword">return</span> self.exception_handler(type, value, traceback)</span><br><span class="line">        <span class="keyword">finally</span>:</span><br><span class="line">            _state.contexts = self.old_contexts</span><br></pre></td></tr></table></figure>

<h2 id="NullContext"><a href="#NullContext" class="headerlink" title="NullContext"></a>NullContext</h2><p>临时构造一个空的全局上下文</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">NullContext</span><span class="params">(object)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__enter__</span><span class="params">(self)</span>:</span></span><br><span class="line">        self.old_contexts = _state.contexts</span><br><span class="line">        _state.contexts = ()</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__exit__</span><span class="params">(self, type, value, traceback)</span>:</span></span><br><span class="line">        _state.contexts = self.old_contexts</span><br></pre></td></tr></table></figure>

<h2 id="wrap"><a href="#wrap" class="headerlink" title="wrap"></a>wrap</h2><ol>
<li>比较当时的全局上下文（_state.contexts）和闭包中保存的上下文 (contexts)<ol>
<li>如果当前上下文长度长，表面执行环境需要重新构造</li>
<li>如果有两者有任何一个上下文不同，执行环境也要重新构造<ol>
<li>新建一个 NullContext(), 清除当前的_state.contexts(保存原来的，提出时复原)</li>
<li>以此为基础构造一个 contexts 上下文链</li>
</ol>
</li>
<li>如果 contexts 是 当前上下文的一个 prefix，则将当前上下文的后续部分作为上下文链，前面共有的无需再构造</li>
</ol>
</li>
<li>在新的上下文链（new_contexts）上执行 with 操作，保证 callback 的执行环境与当时保存时的一模一样</li>
</ol>
<p>之所以进行这样复杂的操作，是为了对某些前面执行环境相同的情况省略前面的构造，节省时间，否则，可以用一行代替：</p>
<p><code>new_contexts = ([NullContext()] + [cls(arg) for (cls,arg) in contexts])</code></p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">wrap</span><span class="params">(fn)</span>:</span></span><br><span class="line">    <span class="keyword">if</span> fn <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">wrapped</span><span class="params">(callback, contexts, *args, **kwargs)</span>:</span></span><br><span class="line">        <span class="comment"># 函数实际调用时，上下文环境发生了变化，与`contexts = _state.contexts`已经有所不同</span></span><br><span class="line">        <span class="keyword">if</span> (len(_state.contexts) &gt; len(contexts) <span class="keyword">or</span></span><br><span class="line">            any(a[<span class="number">1</span>] <span class="keyword">is</span> <span class="keyword">not</span> b[<span class="number">1</span>]</span><br><span class="line">                <span class="keyword">for</span> a, b <span class="keyword">in</span> itertools.izip(_state.contexts, contexts))):</span><br><span class="line">            <span class="comment"># contexts have been removed or changed, so start over</span></span><br><span class="line">            new_contexts = ([NullContext()] +</span><br><span class="line">                            [cls(arg) <span class="keyword">for</span> (cls,arg) <span class="keyword">in</span> contexts])</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            new_contexts = [cls(arg)</span><br><span class="line">                            <span class="keyword">for</span> (cls, arg) <span class="keyword">in</span> contexts[len(_state.contexts):]]</span><br><span class="line">        <span class="keyword">if</span> len(new_contexts) &gt; <span class="number">1</span>:</span><br><span class="line">            <span class="keyword">with</span> contextlib.nested(*new_contexts):</span><br><span class="line">                callback(*args, **kwargs)</span><br><span class="line">        <span class="keyword">elif</span> new_contexts:</span><br><span class="line">            <span class="keyword">with</span> new_contexts[<span class="number">0</span>]:</span><br><span class="line">                callback(*args, **kwargs)</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            callback(*args, **kwargs)</span><br><span class="line">    <span class="keyword">if</span> getattr(fn, <span class="string">'stack_context_wrapped'</span>, <span class="literal">False</span>):</span><br><span class="line">        <span class="keyword">return</span> fn</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 保存上下文环境</span></span><br><span class="line">    contexts = _state.contexts</span><br><span class="line">    result = functools.partial(wrapped, fn, contexts)</span><br><span class="line">    result.stack_context_wrapped = <span class="literal">True</span></span><br><span class="line">    <span class="keyword">return</span> result</span><br></pre></td></tr></table></figure>

<h2 id="copyright"><a href="#copyright" class="headerlink" title="copyright"></a>copyright</h2><p>author：bigfish<br>copyright: <a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank" rel="noopener">许可协议 知识共享署名 - 非商业性使用 4.0 国际许可协议</a></p>
<hr>
<p>Sync From: <a href="https://github.com/TheBigFish/blog/issues/10" target="_blank" rel="noopener">https://github.com/TheBigFish/blog/issues/10</a></p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/12/21/-tornado-yuan-ma-zhi-stackcontext%EF%BC%88-yi-%EF%BC%89/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="bigfish">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="理想-咸鱼">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/12/21/-tornado-yuan-ma-zhi-stackcontext%EF%BC%88-yi-%EF%BC%89/" itemprop="url">tornado源码之StackContext（一）</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2018-12-21T16:50:38+08:00">
                2018-12-21
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Words count in article&#58;</span>
                
                <span title="Words count in article">
                  1.1k
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Reading time &asymp;</span>
                
                <span title="Reading time">
                  5
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h1 id="tornado-源码之-StackContext（一）"><a href="#tornado-源码之-StackContext（一）" class="headerlink" title="tornado 源码之 StackContext（一）"></a>tornado 源码之 StackContext（一）</h1><blockquote>
<p>tornado 的异步上下文机制分析</p>
</blockquote>
<h2 id="contents"><a href="#contents" class="headerlink" title="contents"></a>contents</h2><ul>
<li><a href="#tornado-%E6%BA%90%E7%A0%81%E4%B9%8B-stackcontext%E4%B8%80">tornado 源码之 StackContext（一）</a><ul>
<li><a href="#contents">contents</a></li>
<li><a href="#myioloop">MyIOLoop</a></li>
<li><a href="#%E5%BC%82%E6%AD%A5%E5%9B%9E%E8%B0%83%E5%BC%82%E5%B8%B8%E7%9A%84%E6%8D%95%E8%8E%B7">异步回调异常的捕获</a></li>
<li><a href="#%E4%BD%BF%E7%94%A8-wrap">使用 wrap</a></li>
<li><a href="#%E4%BD%BF%E7%94%A8-contextlib">使用 contextlib</a></li>
<li><a href="#inspired-by">inspired by</a></li>
<li><a href="#copyright">copyright</a></li>
</ul>
</li>
</ul>
<p>我们实现一个简单的 MyIOLoop 类，模仿 tornado 的 IOLoop，实现异步回调<br>实现一个简单的 MyStackContext 类，模仿 tornado 的 StackContext，实现上下文</p>
<h2 id="MyIOLoop"><a href="#MyIOLoop" class="headerlink" title="MyIOLoop"></a>MyIOLoop</h2><p>模拟 tornado IOLoop</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyIOLoop</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self)</span>:</span></span><br><span class="line">        self._callbacks = []</span><br><span class="line"></span><br><span class="line"><span class="meta">    @classmethod</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">instance</span><span class="params">(cls)</span>:</span></span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">not</span> hasattr(cls, <span class="string">"_instance"</span>):</span><br><span class="line">            cls._instance = cls()</span><br><span class="line">        <span class="keyword">return</span> cls._instance</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">add_callback</span><span class="params">(self, call_back)</span>:</span></span><br><span class="line">        self._callbacks.append(call_back)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">start</span><span class="params">(self)</span>:</span></span><br><span class="line">        callbacks = self._callbacks</span><br><span class="line">        self._callbacks = []</span><br><span class="line">        <span class="keyword">for</span> call_back <span class="keyword">in</span> callbacks:</span><br><span class="line">            call_back()</span><br></pre></td></tr></table></figure>

<h2 id="异步回调异常的捕获"><a href="#异步回调异常的捕获" class="headerlink" title="异步回调异常的捕获"></a>异步回调异常的捕获</h2><p>由输出可以看到，回调函数 call_func 中抛出的异常，在 main 函数中无法被捕获<br>main 函数只能捕获当时运行的 async_task 中抛出的异常, async_task 只是向 MyIOLoop 注册了一个回调，并没有当场调用回调<br>call_func 函数最终在 MyIOLoop.start 中调用，其异常没有被捕获</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">my_io_loop = MyIOLoop.instance()</span><br><span class="line">times = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">call_func</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">'run call_func'</span></span><br><span class="line">    <span class="keyword">raise</span> ValueError(<span class="string">'except in call_func'</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">async_task</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">global</span> times</span><br><span class="line">    times += <span class="number">1</span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">'run async task &#123;&#125;'</span>.format(times)</span><br><span class="line">    my_io_loop.add_callback(call_back=call_func)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">main</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        async_task()</span><br><span class="line">    <span class="keyword">except</span> Exception <span class="keyword">as</span> e:</span><br><span class="line">        <span class="keyword">print</span> <span class="string">'main exception &#123;&#125;'</span>.format(e)</span><br><span class="line">        <span class="keyword">print</span> <span class="string">'end'</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line">    main()</span><br><span class="line">    my_io_loop.start()</span><br><span class="line"></span><br><span class="line"><span class="comment"># run async task 1</span></span><br><span class="line"><span class="comment"># Traceback (most recent call last):</span></span><br><span class="line"><span class="comment"># run call_func</span></span><br><span class="line"><span class="comment">#   File "E:/learn/python/simple-python/stack_context_example.py", line 56, in &lt;module&gt;</span></span><br><span class="line"><span class="comment">#     my_io_loop.start()</span></span><br><span class="line"><span class="comment">#   File "E:/learn/python/simple-python/stack_context_example.py", line 26, in start</span></span><br><span class="line"><span class="comment">#     call_back()</span></span><br><span class="line"><span class="comment">#   File "E:/learn/python/simple-python/stack_context_example.py", line 36, in call_func</span></span><br><span class="line"><span class="comment">#     raise ValueError('except in call_func')</span></span><br><span class="line"><span class="comment"># ValueError: except in call_func</span></span><br></pre></td></tr></table></figure>

<h2 id="使用-wrap"><a href="#使用-wrap" class="headerlink" title="使用 wrap"></a>使用 wrap</h2><p>可以使用 wrap 的方式，把函数调用和异常捕捉写在一起，回调实际调用的是带异常捕捉的函数 wrapper</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">my_io_loop = MyIOLoop.instance()</span><br><span class="line">times = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">call_func</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">'run call_func'</span></span><br><span class="line">    <span class="keyword">raise</span> ValueError(<span class="string">'except in call_func'</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">wrapper</span><span class="params">(func)</span>:</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        func()</span><br><span class="line">    <span class="keyword">except</span> Exception <span class="keyword">as</span> e:</span><br><span class="line">        <span class="keyword">print</span> <span class="string">'wrapper exception &#123;&#125;'</span>.format(e)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">async_task</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">global</span> times</span><br><span class="line">    times += <span class="number">1</span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">'run async task &#123;&#125;'</span>.format(times)</span><br><span class="line">    my_io_loop.add_callback(call_back=functools.partial(wrapper, call_func))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">main</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        async_task()</span><br><span class="line">    <span class="keyword">except</span> Exception <span class="keyword">as</span> e:</span><br><span class="line">        <span class="keyword">print</span> <span class="string">'main exception &#123;&#125;'</span>.format(e)</span><br><span class="line">        <span class="keyword">print</span> <span class="string">'end'</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line">    main()</span><br><span class="line">    my_io_loop.start()</span><br><span class="line"></span><br><span class="line"><span class="comment"># run async task 1</span></span><br><span class="line"><span class="comment"># run call_func</span></span><br><span class="line"><span class="comment"># wrapper exception except in call_func</span></span><br></pre></td></tr></table></figure>

<p>由此，可以想到，构造一个上下文环境，使用全局变量保存这个执行环境，等回调函数执行的时候，构造出这个环境</p>
<h2 id="使用-contextlib"><a href="#使用-contextlib" class="headerlink" title="使用 contextlib"></a>使用 contextlib</h2><p>下面模仿了 tornado 异步上下文实现机制</p>
<ol>
<li>MyStackContext 使用 __enter__ __exit__ 支持上下文</li>
<li>MyStackContext 构造函数参数为一个上下文对象</li>
<li>with MyStackContext(context) 进行如下动作：<br><strong>在 MyStackContext(context) 构造时，把 context 注册进全局工厂 MyStackContext.context_factory</strong><ol>
<li>进入 MyStackContext 的__enter</li>
<li>构造一个 context 对象</li>
<li>调用 context 对象的 __enter，进入真正 context 上下文</li>
<li>执行 context 上下文，my_context yield 语句前的部分</li>
<li>执行上下文包裹的语句，async_task</li>
<li>async_task 中 add_callback，实际保存的 wrap, wrap 将此时的全局上下文环境 MyStackContext.context_factory 保存，以方便 call_back 调用</li>
<li>调用 context 对象的 __exit, 退出 context 上下文</li>
<li>进入 MyStackContext 的__exit</li>
</ol>
</li>
<li>my_io_loop.start() 执行, 调用注册的 _call_back</li>
<li>实际调用 wrapped 函数<ol>
<li>获取保存的 context 环境</li>
<li>with context</li>
<li>调用真正的 callback</li>
</ol>
</li>
</ol>
<p>这样，在 main 函数中执行</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">with</span> MyStackContext(my_context):</span><br><span class="line">    async_task()</span><br></pre></td></tr></table></figure>

<p>构造一个执行上下文 my_context，异步函数将在这个上下文中调用<br>效果上相当于在 my_context 这个上下文环境中调用 async_task<br>类似：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">my_context</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">'---enter my_context---&gt;&gt;'</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        async_task()</span><br><span class="line">    <span class="keyword">except</span> Exception <span class="keyword">as</span> e:</span><br><span class="line">        <span class="keyword">print</span> <span class="string">'handler except: &#123;&#125;'</span>.format(e)</span><br><span class="line">    <span class="keyword">finally</span>:</span><br><span class="line">        <span class="keyword">print</span> <span class="string">'&lt;&lt;---exit my_context ---'</span></span><br></pre></td></tr></table></figure>

<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> contextlib</span><br><span class="line"><span class="keyword">import</span> functools</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyIOLoop</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self)</span>:</span></span><br><span class="line">        self._callbacks = []</span><br><span class="line"></span><br><span class="line"><span class="meta">    @classmethod</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">instance</span><span class="params">(cls)</span>:</span></span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">not</span> hasattr(cls, <span class="string">"_instance"</span>):</span><br><span class="line">            cls._instance = cls()</span><br><span class="line">        <span class="keyword">return</span> cls._instance</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">add_callback</span><span class="params">(self, call_back)</span>:</span></span><br><span class="line">        self._callbacks.append(wrap(call_back))</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">start</span><span class="params">(self)</span>:</span></span><br><span class="line">        callbacks = self._callbacks</span><br><span class="line">        self._callbacks = []</span><br><span class="line">        <span class="keyword">for</span> call_back <span class="keyword">in</span> callbacks:</span><br><span class="line">            self._call_back(call_back)</span><br><span class="line"></span><br><span class="line"><span class="meta">    @staticmethod</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">_call_back</span><span class="params">(func)</span>:</span></span><br><span class="line">        func()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyStackContext</span><span class="params">(object)</span>:</span></span><br><span class="line">    context_factory = []</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, context)</span>:</span></span><br><span class="line">        <span class="keyword">if</span> context:</span><br><span class="line">            MyStackContext.context_factory.append(context)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__enter__</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            self.context = self.context_factory[<span class="number">0</span>]()</span><br><span class="line">            self.context.__enter__()</span><br><span class="line">        <span class="keyword">except</span> Exception:</span><br><span class="line">            <span class="keyword">raise</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__exit__</span><span class="params">(self, type, value, traceback)</span>:</span></span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            <span class="keyword">return</span> self.context.__exit__(type, value, traceback)</span><br><span class="line">        <span class="keyword">finally</span>:</span><br><span class="line">            <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">wrap</span><span class="params">(fn)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">wrapped</span><span class="params">(callback, contexts, *args, **kwargs)</span>:</span></span><br><span class="line">        context = contexts[<span class="number">0</span>]()</span><br><span class="line">        <span class="keyword">with</span> context:</span><br><span class="line">            callback(*args, **kwargs)</span><br><span class="line"></span><br><span class="line">    contexts = MyStackContext.context_factory</span><br><span class="line">    result = functools.partial(wrapped, fn, contexts)</span><br><span class="line">    <span class="keyword">return</span> result</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">my_io_loop = MyIOLoop.instance()</span><br><span class="line"></span><br><span class="line">times = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">call_func</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">'run call_func'</span></span><br><span class="line">    <span class="keyword">raise</span> ValueError(<span class="string">'except in call_func'</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">async_task</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">global</span> times</span><br><span class="line">    times += <span class="number">1</span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">'run async task &#123;&#125;'</span>.format(times)</span><br><span class="line">    my_io_loop.add_callback(call_back=call_func)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">@contextlib.contextmanager</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">my_context</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">'---enter my_context---&gt;&gt;'</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="keyword">yield</span></span><br><span class="line">    <span class="keyword">except</span> Exception <span class="keyword">as</span> e:</span><br><span class="line">        <span class="keyword">print</span> <span class="string">'handler except: &#123;&#125;'</span>.format(e)</span><br><span class="line">    <span class="keyword">finally</span>:</span><br><span class="line">        <span class="keyword">print</span> <span class="string">'&lt;&lt;---exit my_context ---'</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">main</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">with</span> MyStackContext(my_context):</span><br><span class="line">        async_task()</span><br><span class="line">    <span class="keyword">print</span> <span class="string">'end main'</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line">    main()</span><br><span class="line">    my_io_loop.start()</span><br><span class="line"></span><br><span class="line"><span class="comment"># ---enter my_context---&gt;&gt;</span></span><br><span class="line"><span class="comment"># run async task 1</span></span><br><span class="line"><span class="comment"># &lt;&lt;---exit my_context ---</span></span><br><span class="line"><span class="comment"># end main</span></span><br><span class="line"><span class="comment"># ---enter my_context---&gt;&gt;</span></span><br><span class="line"><span class="comment"># run call_func</span></span><br><span class="line"><span class="comment"># handler except: except in call_func</span></span><br><span class="line"><span class="comment"># &lt;&lt;---exit my_context ---</span></span><br></pre></td></tr></table></figure>

<h2 id="inspired-by"><a href="#inspired-by" class="headerlink" title="inspired by"></a>inspired by</h2><p><a href="https://www.jianshu.com/p/3e58f977b908" target="_blank" rel="noopener">Tornado 源码分析（二）异步上下文管理（StackContext）</a></p>
<h2 id="copyright"><a href="#copyright" class="headerlink" title="copyright"></a>copyright</h2><p>author：bigfish<br>copyright: <a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank" rel="noopener">许可协议 知识共享署名 - 非商业性使用 4.0 国际许可协议</a></p>
<hr>
<p>Sync From: <a href="https://github.com/TheBigFish/blog/issues/9" target="_blank" rel="noopener">https://github.com/TheBigFish/blog/issues/9</a></p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
  </section>

  
  <nav class="pagination">
    <span class="page-number current">1</span><a class="page-number" href="/page/2/">2</a><a class="extend next" rel="next" href="/page/2/">&lt;i class&#x3D;&quot;fa fa-angle-right&quot;&gt;&lt;&#x2F;i&gt;</a>
  </nav>



          </div>
          


          

        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      

      <section class="site-overview-wrap sidebar-panel sidebar-panel-active">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <p class="site-author-name" itemprop="name">bigfish</p>
              <p class="site-description motion-element" itemprop="description">一些简单的想法</p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/archives/%7C%7C%20archive">
              
                  <span class="site-state-item-count">18</span>
                  <span class="site-state-item-name">posts</span>
                </a>
              </div>
            

            

            
              
              
              <div class="site-state-item site-state-tags">
                <a href="/tags/index.html">
                  <span class="site-state-item-count">5</span>
                  <span class="site-state-item-name">tags</span>
                </a>
              </div>
            

          </nav>

          
            <div class="feed-link motion-element">
              <a href="/atom.xml" rel="alternate">
                <i class="fa fa-rss"></i>
                RSS
              </a>
            </div>
          

          <div class="links-of-author motion-element">
            
          </div>

          
          

          
          

          

        </div>
      </section>

      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2020</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">bigfish</span>

  
</div>


  <div class="powered-by">Powered by <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a></div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">Theme &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Pisces</a> v5.1.3</div>




<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>




        
<div class="busuanzi-count">
  <script async src="https://dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>

  
    <span class="site-uv">
      访客数
      <span class="busuanzi-value" id="busuanzi_value_site_uv"></span>
      人
    </span>
  

  
    <span class="site-pv">
      总访问量
      <span class="busuanzi-value" id="busuanzi_value_site_pv"></span>
      次
    </span>
  
</div>








        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>

  
  <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>

  
  <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.3"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.3"></script>



  
  


  <script type="text/javascript" src="/js/src/affix.js?v=5.1.3"></script>

  <script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.3"></script>



  

  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.3"></script>



  


  




	





  





  










  





  

  

  

  

  

  

</body>
</html>
